using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace CollabApp.Domain.Entities.Game;

/// <summary>
/// 游戏操作记录实体 - 记录玩家在画线圈地游戏中的具体操作行为
/// 用于游戏回放、数据分析、作弊检测等功能
/// </summary>
[Table("game_actions")]
public class GameAction : BaseEntity
{
    /// <summary>
    /// 游戏ID - 外键，关联到具体的游戏实例
    /// </summary>
    [Required]
    [Column("game_id")]
    public Guid GameId { get; private set; }

    /// <summary>
    /// 用户ID - 外键，关联到执行操作的用户
    /// </summary>
    [Required]
    [Column("user_id")]
    public Guid UserId { get; private set; }

    /// <summary>
    /// 操作类型 - 描述玩家执行的操作（移动、开始画线、完成圈地、使用道具、死亡等）
    /// </summary>
    [Required]
    [MaxLength(50)]
    [Column("action_type")]
    public string ActionType { get; private set; } = string.Empty;

    /// <summary>
    /// 操作数据 - JSON格式存储操作的详细参数
    /// 包含路径坐标、道具类型、碰撞信息等具体数据
    /// </summary>
    [Column("action_data", TypeName = "json")]
    public string? ActionData { get; private set; }

    /// <summary>
    /// 操作时间戳 - 操作执行的精确时间（毫秒级）
    /// 用于游戏回放的时序控制和数据同步
    /// </summary>
    [Column("timestamp")]
    public long Timestamp { get; private set; }

    /// <summary>
    /// X坐标 - 操作发生的X坐标位置
    /// 用于快速查询和空间索引
    /// </summary>
    [Column("x")]
    [Precision(10, 2)]
    public decimal X { get; private set; }

    /// <summary>
    /// Y坐标 - 操作发生的Y坐标位置
    /// 用于快速查询和空间索引
    /// </summary>
    [Column("y")]
    [Precision(10, 2)]
    public decimal Y { get; private set; }

    /// <summary>
    /// 操作结果 - 记录操作执行后的结果或状态变化
    /// 例如：圈地成功面积、死亡原因、道具效果等
    /// </summary>
    [Column("result")]
    [MaxLength(500)]
    public string? Result { get; private set; }

    /// <summary>
    /// 影响的领地面积变化
    /// </summary>
    [Column("territory_area_change")]
    [Precision(10, 2)]
    public decimal TerritoryAreaChange { get; private set; } = 0;

    /// <summary>
    /// 移动速度（记录当时的移动速度，包含道具加成）
    /// </summary>
    [Column("movement_speed")]
    [Precision(5, 2)]
    public decimal MovementSpeed { get; private set; } = 1.0m;

    /// <summary>
    /// 是否在敌方领地内执行操作
    /// </summary>
    [Column("in_enemy_territory")]
    public bool InEnemyTerritory { get; private set; } = false;

    // ============ 构造函数 ============

    /// <summary>
    /// 无参构造函数 - EF Core 必需
    /// </summary>
    private GameAction() { }

    /// <summary>
    /// 私有构造函数 - 仅限工厂方法调用
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="userId">用户ID</param>
    /// <param name="actionType">操作类型</param>
    /// <param name="x">X坐标</param>
    /// <param name="y">Y坐标</param>
    /// <param name="timestamp">时间戳</param>
    /// <param name="actionData">操作数据</param>
    /// <param name="result">操作结果</param>
    private GameAction(Guid gameId, Guid userId, string actionType, 
                       decimal x, decimal y, long timestamp,
                       string? actionData = null, string? result = null)
    {
        GameId = gameId;
        UserId = userId;
        ActionType = actionType;
        X = x;
        Y = y;
        Timestamp = timestamp;
        ActionData = actionData;
        Result = result;
    }

    // ============ 导航属性 ============
    
    /// <summary>
    /// 导航属性 - 关联的游戏实例
    /// </summary>
    [ForeignKey("GameId")]
    public virtual Game Game { get; set; } = null!;
    
    /// <summary>
    /// 导航属性 - 关联的用户信息
    /// </summary>
    [ForeignKey("UserId")]
    public virtual Auth.User User { get; set; } = null!;

    // ============ 工厂方法 ============

    /// <summary>
    /// 创建移动操作记录
    /// </summary>
    public static GameAction CreateMoveAction(Guid gameId, Guid userId, 
                                              decimal x, decimal y, decimal speed = 1.0m,
                                              bool inEnemyTerritory = false, long? timestamp = null)
    {
        var action = new GameAction(gameId, userId, "move", x, y, 
                                    timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
        action.MovementSpeed = speed;
        action.InEnemyTerritory = inEnemyTerritory;
        return action;
    }

    /// <summary>
    /// 创建开始画线操作记录
    /// </summary>
    public static GameAction CreateStartDrawingAction(Guid gameId, Guid userId, 
                                                      decimal x, decimal y, long? timestamp = null)
    {
        return new GameAction(gameId, userId, "start_drawing", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
    }

    /// <summary>
    /// 创建画线路径点操作记录
    /// </summary>
    public static GameAction CreateDrawPathAction(Guid gameId, Guid userId, 
                                                  decimal x, decimal y, string pathData, 
                                                  long? timestamp = null)
    {
        return new GameAction(gameId, userId, "draw_path", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              pathData);
    }

    /// <summary>
    /// 创建完成圈地操作记录
    /// </summary>
    public static GameAction CreateCompleteTerritory(Guid gameId, Guid userId, 
                                                     decimal x, decimal y, decimal areaGained, 
                                                     string territoryData, long? timestamp = null)
    {
        var action = new GameAction(gameId, userId, "complete_territory", x, y, 
                                    timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                                    territoryData, $"获得领地面积: {areaGained}");
        action.TerritoryAreaChange = areaGained;
        return action;
    }

    /// <summary>
    /// 创建死亡操作记录
    /// </summary>
    public static GameAction CreateDeathAction(Guid gameId, Guid userId, 
                                               decimal x, decimal y, string deathReason,
                                               Guid? killerUserId = null, long? timestamp = null)
    {
        var actionData = killerUserId.HasValue ? 
            $"{{\"killer_user_id\": \"{killerUserId}\", \"reason\": \"{deathReason}\"}}" : 
            $"{{\"reason\": \"{deathReason}\"}}";

        return new GameAction(gameId, userId, "death", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              actionData, deathReason);
    }

    /// <summary>
    /// 创建复活操作记录
    /// </summary>
    public static GameAction CreateRespawnAction(Guid gameId, Guid userId, 
                                                 decimal spawnX, decimal spawnY, long? timestamp = null)
    {
        return new GameAction(gameId, userId, "respawn", spawnX, spawnY, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              null, "玩家复活");
    }

    /// <summary>
    /// 创建道具拾取操作记录
    /// </summary>
    public static GameAction CreatePickupPowerUpAction(Guid gameId, Guid userId, 
                                                       decimal x, decimal y, string powerUpType,
                                                       long? timestamp = null)
    {
        return new GameAction(gameId, userId, "pickup_powerup", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              powerUpType, $"拾取道具: {powerUpType}");
    }

    /// <summary>
    /// 创建道具使用操作记录
    /// </summary>
    public static GameAction CreateUsePowerUpAction(Guid gameId, Guid userId, 
                                                    decimal x, decimal y, string powerUpType,
                                                    string effect, long? timestamp = null)
    {
        return new GameAction(gameId, userId, "use_powerup", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              powerUpType, $"使用道具 {powerUpType}: {effect}");
    }

    /// <summary>
    /// 创建击杀操作记录
    /// </summary>
    public static GameAction CreateKillAction(Guid gameId, Guid killerUserId, 
                                              decimal x, decimal y, Guid victimUserId,
                                              long? timestamp = null)
    {
        var actionData = $"{{\"victim_user_id\": \"{victimUserId}\"}}";
        
        return new GameAction(gameId, killerUserId, "kill", x, y, 
                              timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                              actionData, "截断击杀");
    }

    /// <summary>
    /// 创建领地被吞噬操作记录
    /// </summary>
    public static GameAction CreateTerritoryEngulfedAction(Guid gameId, Guid userId, 
                                                           decimal x, decimal y, decimal areaLost,
                                                           Guid engulferUserId, long? timestamp = null)
    {
        var actionData = $"{{\"engulfer_user_id\": \"{engulferUserId}\"}}";
        var action = new GameAction(gameId, userId, "territory_engulfed", x, y, 
                                    timestamp ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 
                                    actionData, $"领地被吞噬，失去面积: {areaLost}");
        action.TerritoryAreaChange = -areaLost;
        return action;
    }

    // ============ 业务方法 ============

    /// <summary>
    /// 更新操作结果
    /// </summary>
    /// <param name="result">操作结果</param>
    public void UpdateResult(string result)
    {
        Result = result;
    }

    /// <summary>
    /// 检查是否为移动类操作
    /// </summary>
    /// <returns>是否为移动操作</returns>
    public bool IsMovementAction()
    {
        return ActionType == "move" || ActionType == "start_drawing" || ActionType == "draw_path";
    }

    /// <summary>
    /// 检查是否为画线操作
    /// </summary>
    /// <returns>是否为画线操作</returns>
    public bool IsDrawingAction()
    {
        return ActionType == "start_drawing" || ActionType == "draw_path" || ActionType == "complete_territory";
    }

    /// <summary>
    /// 检查是否为道具操作
    /// </summary>
    /// <returns>是否为道具操作</returns>
    public bool IsPowerUpAction()
    {
        return ActionType == "pickup_powerup" || ActionType == "use_powerup";
    }

    /// <summary>
    /// 检查是否为战斗相关操作
    /// </summary>
    /// <returns>是否为战斗操作</returns>
    public bool IsCombatAction()
    {
        return ActionType == "death" || ActionType == "kill" || ActionType == "respawn";
    }

    /// <summary>
    /// 检查是否为领地相关操作
    /// </summary>
    /// <returns>是否为领地操作</returns>
    public bool IsTerritoryAction()
    {
        return ActionType == "complete_territory" || ActionType == "territory_engulfed";
    }

    /// <summary>
    /// 获取操作类型的友好显示名称
    /// </summary>
    /// <returns>友好的操作名称</returns>
    public string GetFriendlyActionType()
    {
        return ActionType switch
        {
            "move" => "移动",
            "start_drawing" => "开始画线",
            "draw_path" => "画线中",
            "complete_territory" => "完成圈地",
            "death" => "死亡",
            "respawn" => "复活",
            "kill" => "击杀",
            "pickup_powerup" => "拾取道具",
            "use_powerup" => "使用道具",
            "territory_engulfed" => "领地被吞噬",
            _ => ActionType
        };
    }

    /// <summary>
    /// 计算与另一个操作的时间间隔
    /// </summary>
    /// <param name="other">另一个操作</param>
    /// <returns>时间间隔（毫秒）</returns>
    public long GetTimeDifference(GameAction other)
    {
        return Math.Abs(Timestamp - other.Timestamp);
    }

    /// <summary>
    /// 计算与另一个操作的距离
    /// </summary>
    /// <param name="other">另一个操作</param>
    /// <returns>距离</returns>
    public double GetDistance(GameAction other)
    {
        var dx = (double)(X - other.X);
        var dy = (double)(Y - other.Y);
        return Math.Sqrt(dx * dx + dy * dy);
    }

    /// <summary>
    /// 获取操作发生的时间（从游戏开始计算）
    /// </summary>
    /// <param name="gameStartTime">游戏开始时间戳</param>
    /// <returns>相对时间（毫秒）</returns>
    public long GetRelativeTime(long gameStartTime)
    {
        return Timestamp - gameStartTime;
    }

    /// <summary>
    /// 检查是否为可疑操作（用于反作弊）
    /// </summary>
    /// <param name="previousAction">前一个操作</param>
    /// <returns>是否可疑</returns>
    public bool IsSuspiciousAction(GameAction? previousAction)
    {
        if (previousAction == null) return false;

        // 检查移动速度是否异常
        if (IsMovementAction() && previousAction.IsMovementAction())
        {
            var distance = GetDistance(previousAction);
            var timeDiff = GetTimeDifference(previousAction);
            if (timeDiff > 0)
            {
                var speed = distance / (timeDiff / 1000.0); // 像素/秒
                var maxNormalSpeed = (double)(MovementSpeed * 200); // 基础速度200像素/秒
                
                if (speed > maxNormalSpeed * 2) // 超过正常速度2倍认为可疑
                    return true;
            }
        }

        // 检查操作频率是否异常
        if (GetTimeDifference(previousAction) < 10) // 10毫秒内连续操作可疑
        {
            return true;
        }

        return false;
    }
}
